home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 220 / 220.xpi / chrome / flashgot.jar / content / flashgot / flashgotOverlay.js < prev    next >
Encoding:
JavaScript  |  2010-01-24  |  32.9 KB  |  1,053 lines

  1. /***** BEGIN LICENSE BLOCK *****
  2.  
  3.     FlashGot - a Firefox extension for external download managers integration
  4.     Copyright (C) 2004-2009 Giorgio Maone - g.maone@informaction.com
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.                              
  20. ***** END LICENSE BLOCK *****/
  21.  
  22. var gFlashGot = {
  23.     
  24.   onload: function(ev) {
  25.     ev.currentTarget.removeEventListener(ev.type, arguments.callee, false);
  26.     try {
  27.       gFlashGot.init();
  28.     } catch(e) {
  29.       dump("FlashGot init error: " + e.message);
  30.       gFlashGot.log("Unrecoverable init error: " + e.message + " --- " + e.stack);
  31.     }
  32.   },
  33.   
  34.   
  35.   hoverElement: null,
  36.   
  37.   _isContentEvent: function(ev) {
  38.     var d = ev.originalTarget.ownerDocument;
  39.     return d && d.defaultView && d.defaultView.top == window.content;
  40.   },
  41.   
  42.   init: function() {
  43.     if(!gFlashGotService) throw new Error("FlashGotService not registered!");
  44.     
  45.     gFlashGotService.dom._winType = document.documentElement.getAttribute("windowtype");
  46.     
  47.     // install listeners
  48.     gFlashGot.isMouseDown = false;
  49.     var target = window.gBrowser || window;
  50.     
  51.     if (target.tabContainer) {
  52.         target.tabContainer.addEventListener("TabSelect", this.updateMediaStatus, false);
  53.     }
  54.     
  55.     
  56.     
  57.     target.addEventListener("load", this.updateMediaStatus, true);
  58.     
  59.     target.addEventListener("mousedown", function(ev) {
  60.       if (!gFlashGot._isContentEvent(ev)) return;
  61.       gFlashGot.isMouseDown = true;
  62.       gFlashGot.hoverElement = ev.originalTarget;
  63.     }, false);
  64.     
  65.     target.addEventListener("mouseover", function(ev) {
  66.       if(!gFlashGot.isMouseDown) gFlashGot.hoverElement = ev.originalTarget;
  67.     }, false);
  68.     
  69.     target.addEventListener("submit", function(ev) {
  70.       if (!gFlashGot._isContentEvent(ev)) return;
  71.       var f = ev.originalTarget;
  72.       if(/#FlashGot_form$/.test(f.action) || 
  73.           f.ownerDocument.defaultView.location.hash == "#FlashGot_Form")
  74.         gFlashGotService.interceptor.forceAutoStart = true;
  75.     }, false);
  76.  
  77.     target.addEventListener("mouseup", function(ev) {
  78.       gFlashGot.isMouseDown = false;
  79.       
  80.       if (!gFlashGot._isContentEvent(ev)) return;
  81.       
  82.       gFlashGotService.interceptor.bypassAutoStart = false;
  83.       gFlashGotService.interceptor.forceAutoStart = false;
  84.       if(ev.altKey && !(ev.ctrlKey || ev.metaKey)) {
  85.         function prevent() {
  86.           ev.preventDefault();
  87.           ev.stopPropagation();
  88.           gFlashGot.lastClickCaptureTime = new Date().getTime();
  89.         }
  90.         var invert = gFlashGotService.getPref("invertAltShiftClick", false);
  91.         if((ev.shiftKey && !invert) || (invert && !ev.shiftKey)) {
  92.           gFlashGotService.interceptor.bypassAutoStart =
  93.             gFlashGotService.getPref("bypassCombo", true);
  94.           return;
  95.         } else {
  96.           if(gFlashGotService.getPref("altClick")) {
  97.             try {
  98.               if(gFlashGot.download()) {
  99.                 prevent();
  100.                 return;
  101.               }
  102.             } catch(ex) {}
  103.             gFlashGotService.interceptor.forceAutoStart = true;
  104.           } else {
  105.             return;
  106.           }
  107.         }
  108.         
  109.         ev2 = ev.view.document.createEvent("MouseEvents");
  110.         ev2.initMouseEvent("click",ev.canBubble, ev.cancelable, 
  111.                            ev.view, ev.detail, ev.screenX, ev.screenY, 
  112.                            ev.clientX, ev.clientY, 
  113.                            //ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey,
  114.                            false,false,false,false,
  115.                            ev.button, ev.relatedTarget);
  116.         prevent();
  117.         gFlashGot.hoverElement.dispatchEvent(ev2);
  118.       }
  119.     }, true);
  120.     
  121.     target.addEventListener("click", function(ev) {
  122.       if(ev.altKey && ev.originalTarget.ownerDocument != document &&
  123.         typeof(gFlashGot.lastClickCaptureTime) == "number" && 
  124.         new Date().getTime() - gFlashGot.lastClickCaptureTime < 100
  125.       ) {
  126.         ev.preventDefault();
  127.         ev.stopPropagation();
  128.       }
  129.     }, true);
  130.     
  131.     
  132.     this.contextMenu.addEventListener("popupshowing", function(ev) {
  133.         if(this == ev.explicitOriginalTarget) {
  134.           gFlashGot.prepareContextMenu(ev);
  135.         }
  136.       },false);
  137.     this.contextMenu.addEventListener("popuphidden", function(ev) {
  138.         if(this == ev.explicitOriginalTarget) {
  139.           gFlashGot.disposeContextMenu(ev);
  140.         }
  141.     }, false);
  142.     
  143.     this.toggleMainMenuIcon();
  144.     
  145.     gFlashGotService.checkVersion();
  146.     
  147.     if(typeof(flashgot_doDirtyJobs) == "function") {
  148.       window.setTimeout(flashgot_doDirtyJobs,0);
  149.     }
  150.   }
  151.   log: function(msg) {
  152.     gFlashGotService.log(msg);
  153.   }
  154. ,
  155.   get contextMenu() {
  156.     var cm =
  157.         document.getElementById("contentAreaContextMenu") ||
  158.         document.getElementById("mailContext") || // TB3
  159.         document.getElementById("messagePaneContext"); // TB2 
  160.     if (cm) {
  161.       delete this.contextMenu;
  162.       this.contextMenu = cm;
  163.     }
  164.     return cm;
  165.   }
  166. ,
  167.   switchOption: function(opt) {
  168.     gFlashGotService.setPref(opt, !gFlashGotService.getPref(opt));
  169.   }
  170. ,
  171.   openOptionsDialog: function() {
  172.     window.open("chrome://flashgot/content/flashgotOptions.xul", "flashgotOptions",
  173.       "chrome,dialog,centerscreen,alwaysRaised");
  174.   }
  175. ,
  176.   openAboutDialog: function() {
  177.     window.open("chrome://flashgot/content/about.xul", "flashgotAbout",
  178.       "chrome,dialog,centerscreen");
  179.   }
  180. ,
  181.   browse: function(url) {
  182.     var browser =  window.getBrowser();
  183.     browser.selectedTab = browser.addTab(url);
  184.   }
  185. ,
  186.   browseHomePage: function() {
  187.     this.browse("http://flashgot.net");
  188.   }
  189. ,
  190.   get hideIcons() {
  191.     return gFlashGotService.getPref("hide-icons", false);
  192.   }
  193. ,
  194.   toggleIcon: function(m, hide) {
  195.     if(!m) return;
  196.     const iconicClass = m.tagName + "-iconic";
  197.     const rx=new RegExp("\\b"+iconicClass+"\\b");
  198.     if(hide) {
  199.       m.className=m.className.replace(rx, "").replace(/\bflashgot-icon-(\w+)\b/,'flashgot-noicon-$1');
  200.     } else {
  201.       const cl=m.className;
  202.       if(!rx.test(cl)) {
  203.         m.className=cl.replace(/\bflashgot-noicon-(\w+)\b/,'flashgot-icon-$1')+" "+iconicClass;
  204.       }
  205.     }
  206.   }
  207. ,
  208.   toggleMainMenuIcon: function() {
  209.     this.toggleIcon(document.getElementById("flashgot-menu"),this.hideIcons);
  210.   }
  211. ,
  212.   prepareToolsMenu: function(ev) {
  213.     
  214.     function toggleMenu(id,disabled) {
  215.       id = "flashgot-main-menuitem-" + id;
  216.       var m = document.getElementById(id);
  217.       if(!m) return;
  218.       m.setAttribute("disabled", disabled);
  219.       gFlashGot.toggleIcon(m, hideIcons);
  220.     }
  221.     
  222.     
  223.     
  224.     if(gFlashGotService && !(document.getElementById("flashgot-menu").hidden = gFlashGotService.getPref("hide-menu"))) {
  225.       const dis = !gFlashGotService.DMS.found;
  226.       const hideIcons = this.hideIcons;
  227.       this.updateMediaUI();
  228.       
  229.       toggleMenu("tabs", dis || !this.isTabbed); 
  230.       toggleMenu("all", dis);
  231.       toggleMenu("sel", dis || this.isSelInvalid);
  232.       toggleMenu("buildGallery", false);
  233.       toggleMenu("media", dis || !this.media);
  234.       toggleMenu("opts", false);
  235.       this.prepareOptsMenu(ev.target);
  236.       
  237.     }
  238.   }
  239. ,
  240.   
  241.   prepareContextMenu: function(ev) {
  242.     
  243.     this.toggleMainMenuIcon();
  244.     var menuCount = 0;
  245.    
  246.     function menuSwitch(name, disabled) {
  247.       var menuItem = document.getElementById("flashgot-menuitem-" + name);
  248.       
  249.       if(menuItem && 
  250.         ! ( menuItem.hidden = 
  251.             ( hidden || gFlashGotService.getPref("hide-" + name) ) )
  252.       ) {
  253.        menuItem.setAttribute("disabled", disabled ? "true" : "false");
  254.        if(! (menuItem.hidden=disabled && hideDisabled) ) {
  255.          menuCount++;
  256.        }
  257.        gFlashGot.toggleIcon(menuItem, hideIcons);
  258.       }
  259.     }
  260.     var menuItem = null;
  261.     const defaultDM = gFlashGotService.defaultDM;  
  262.     const dms = gFlashGotService.DMS;
  263.     var dm = dms.found ? dms[defaultDM] : null;
  264.     
  265.     gFlashGotService.restoreNativeUIs(document);
  266.     dm.hideNativeUI(document);
  267.    
  268.     const invalidLink = !this.popupLink;
  269.    
  270.     const invalidSel = this.isSelInvalid;
  271.     
  272.     const noLink = this.linksCount == 0;
  273.     const hideDisabled = gFlashGotService.getPref("hideDisabledCmds");
  274.    
  275.     
  276.     var hidden = !(dms.found && dm);
  277.     const hideIcons = this.hideIcons;
  278.     
  279.     var hideLink = invalidLink || hidden || dm.disabledLink;
  280.     var hideSel = invalidSel || hidden  || dm.disabledSel;
  281.     this.prepareCommandsMenu(document.getElementById("flashgot-menuitem-it"), hideLink && hideSel);
  282.     
  283.     this.updateMediaUI();
  284.     
  285.     menuSwitch("it",  hideLink);
  286.     menuSwitch("sel", hideSel);
  287.     menuSwitch("all", noLink || hidden || dm.disabledAll);
  288.     menuSwitch("tabs", (! (typeof(gBrowser)=="object" 
  289.       && gBrowser.browsers && gBrowser.browsers.length > 1) ) 
  290.                            || hidden || dm.disabledAll);
  291.     menuSwitch("media", hidden || !this.media);
  292.  
  293.     hidden = false;
  294.     menuSwitch("buildGallery", false);
  295.     
  296.     const optsMenu = document.getElementById("flashgot-menu-options");
  297.     this.toggleIcon(optsMenu,hideIcons);
  298.     if(!(optsMenu.hidden = gFlashGotService.getPref("hide-options"))) {
  299.       menuCount++;
  300.     }
  301.     
  302.     const submenu = document.getElementById("flashgot-submenu");
  303.     this.toggleIcon(submenu, hideIcons);
  304.     const subanchor = document.getElementById("flashgot-submenu-anchor");
  305.     const subpop = subanchor.parentNode;
  306.     const sep1 = document.getElementById("flashgot-context-separator");
  307.     const sep2 = document.getElementById("flashgot-context-separator2");
  308.     const menu = sep1.parentNode;
  309.     var next = null;
  310.     
  311.     const nested = gFlashGotService.getPref("nested-menu") && (menuCount > 1);
  312.     submenu.hidden = !nested;
  313.     if(nested) {
  314.       menuCount=0;
  315.       if(!subanchor.nextSibling) {
  316.         menuItem = document.getElementById("flashgot-menuitem-tabs");
  317.         if (menuItem)
  318.             menuItem.setAttribute("accesskey",
  319.                 document.getElementById("flashgot-main-menuitem-tabs").getAttribute("accesskey"));
  320.         for(menuItem = sep1.nextSibling;
  321.             menuItem && (menuItem != sep2); 
  322.             menuItem = next) {
  323.           next = menuItem.nextSibling;
  324.           subpop.appendChild(menuItem);
  325.         }
  326.       }
  327.     } else {
  328.       menuItem = document.getElementById("flashgot-menuitem-tabs");
  329.       if (menuItem) menuItem.removeAttribute("accesskey");
  330.       for(menuItem = subanchor.nextSibling; menuItem; menuItem = next) {
  331.         next = menuItem.nextSibling;
  332.         menu.insertBefore(menuItem, sep2);
  333.       }
  334.     }
  335.     sep1.hidden = menuCount == 0;
  336.   }
  337. ,
  338.   disposeContextMenu: function(ev) {
  339.     gFlashGotService.restoreNativeUIs(document);
  340.   },
  341.   prepareCommandsMenu: function(anchorNode, hideOnly) {
  342.     var node, parentNode = anchorNode.parentNode;
  343.     
  344.     var cmi = (parentNode.getElementsByClassName && parentNode.getElementsByClassName("flashgot-command-menuitem")
  345.                || parentNode.getElementsByTagName("menuitem"));
  346.     
  347.     var j, len;
  348.     
  349.     for(j = cmi.length; j-- > 0;) 
  350.       if (/^flashgot-command-mi-/.test(cmi[j].id))
  351.         parentNode.removeChild(cmi[j]);
  352.     
  353.     if(hideOnly) return;
  354.     
  355.     var mi, dm, id;
  356.     const dms = gFlashGotService.DMS;
  357.     for(j = 0, len = dms.length; j < len; j++) {
  358.       dm = dms[j];
  359.       if(dm.supported && dm.shownInContextMenu) {
  360.         id =  "flashgot-command-mi-" + dm.codeName;
  361.         if (!document.getElementById(id)) {
  362.           mi = document.createElement("menuitem");
  363.           mi.setAttribute("class", "menuitem-iconic flashgot-command-menuitem");
  364.           mi.setAttribute("label", dm.name);
  365.           mi.setAttribute("id", id);
  366.           mi.setAttribute("oncommand", "gFlashGot.downloadSel(this.label) || gFlashGot.downloadPopupLink(this.label)");
  367.           parentNode.insertBefore(mi, anchorNode);
  368.         }
  369.         dm.hideNativeUI(document);
  370.       }
  371.     }
  372.   },
  373.   
  374.   
  375.   prepareOptsMenu: function(parentNode) {
  376.    
  377.     const opts = parentNode.getElementsByTagName("menuitem");
  378.     
  379.     this.toggleIcon(document.getElementById("flashgot-tbb-menuitem-opts"), this.hideIcons);
  380.     
  381.     var menuItem, id, match, lastMenu=null, isTBB=false;
  382.     var j = opts.length;
  383.     while(j-- > 0) {
  384.       menuItem = opts[j];
  385.       if((id=menuItem.id)) {
  386.         if((match = id.match(/opt-(.*)/))) {
  387.           menuItem.setAttribute("checked",
  388.             gFlashGotService.getPref(match[1]) ? "true" : "false");
  389.         } else if((match = id.match(/^flashgot-(\w+)-menuitem-nodms$/))) {
  390.           lastMenu = menuItem;
  391.           isTBB = match[1]=="tbb";
  392.         }
  393.       }
  394.     }
  395.     
  396.     if(!lastMenu) return;
  397.     
  398.     const defaultDM = gFlashGotService.defaultDM;  
  399.     const dms = gFlashGotService.DMS;
  400.     var menuItemId;
  401.     if(dms.found) {
  402.       var idPrefix="flashgot-menuopt-dm-";
  403.       var eventPostfix;
  404.       if(isTBB) {
  405.         idPrefix += "tbb-";
  406.         eventPostfix = "gFlashGot.downloadSel() || gFlashGot.downloadAll()";
  407.       } else {
  408.         eventPostfix = "gFlashGot.downloadSel() || gFlashGot.downloadPopupLink()";
  409.       }
  410.       lastMenu.setAttribute("hidden", "true");
  411.       parentNode = lastMenu.parentNode;
  412.       var dm;
  413.       const miclass = "flashgot-dms-entry";
  414.       // add menu items
  415.       for(j = dms.length; j-- >0;) {
  416.         dm = dms[j];
  417.         if(dm.supported) {
  418.           menuItemId = idPrefix + dm.codeName;
  419.           menuItem = document.getElementById(menuItemId);
  420.           if(!menuItem) {
  421.             menuItem = document.createElement("menuitem");
  422.             menuItem.setAttribute("class", miclass);
  423.             menuItem.setAttribute("id", menuItemId);
  424.             menuItem.setAttribute("type", "radio");
  425.             menuItem.setAttribute("autocheck", "true");
  426.             menuItem.setAttribute("oncommand", 
  427.                 "gFlashGotService.defaultDM = this.label; window.setTimeout(function() { " + 
  428.                   eventPostfix + " }, 0)");
  429.             menuItem.setAttribute("label", dm.name);
  430.             parentNode.insertBefore(menuItem, lastMenu);
  431.           }
  432.           menuItem.setAttribute("checked", (defaultDM == dm.name) ? "true" : "false");
  433.           lastMenu = menuItem;
  434.         }
  435.       }
  436.       // remove menu items
  437.       var nodes=parentNode.getElementsByAttribute("class", miclass);
  438.       for(j=nodes.length; j-->0;) {
  439.         dm=dms[nodes[j].getAttribute("label")];
  440.         if(!(dm && dm.supported)) {
  441.           parentNode.removeChild(nodes[j],true);
  442.         }
  443.       }
  444.     } else {
  445.       lastMenu.removeAttribute("hidden");
  446.     }
  447.   }
  448. ,
  449.   
  450.   
  451.   
  452.   _mediaUI: null,
  453.   updateMediaUI: function() {
  454.     if (!this._mediaUI) {
  455.       this._mediaUI = ["flashgot-menuitem-media", "flashgot-main-menuitem-media","flashgot-media-status"]
  456.         .map(function(id) { return document.getElementById(id); });
  457.     }
  458.     var mm = this.media;
  459.     var count = (mm && mm.length) ? " (" + mm.length + ")" : "";
  460.     var tip = (count && typeof(/ /) == "object") // Fx >= 3, multiline tooltips supported 
  461.         ? mm.map(function(l) { return l.tip }).join("\n")
  462.         : '';
  463.     
  464.     var l;
  465.     for each(var ui in this._mediaUI) {
  466.       if (ui) {
  467.         l = ui.getAttribute("label");
  468.         if (l) ui.label = l.replace(/\s*\(\d+\)$/, '') + count;
  469.         
  470.         if (tip) ui.setAttribute("tooltiptext", tip);
  471.         else ui.removeAttribute("tooltiptext");
  472.         
  473.         if (count) ui.hidden = ui.disabled = false;
  474.       }
  475.     }
  476.     this.updateMediaStatus(true);
  477.   },
  478.   
  479.   updateMediaStatus: function(anim) {
  480.     if (this != gFlashGot) gFlashGot.updateMediaStatus();
  481.     else {
  482.       var ms = this.mediaStatusAnim.widget;
  483.       if (ms) {
  484.         if (gFlashGotService.getPref("media.statusIcon", true)) {
  485.             var m = this.media;
  486.             ms.hidden = ms.disabled = !(m && m.length);
  487.         } else {
  488.             ms.hidden = true;
  489.         }
  490.         this.mediaStatusAnim.run(!anim);
  491.       }
  492.     }
  493.   },
  494.   
  495.   mediaStatusAnim: {
  496.     interval: 0,
  497.     lastShowing: false,
  498.     cycles: 0,
  499.     get widget() {
  500.       delete this.widget;
  501.       return this.widget = document.getElementById("flashgot-media-status");  
  502.     },
  503.     run: function(once) {
  504.       var w = this.widget;
  505.       if (!w) return;
  506.       var showing = !w.hidden;
  507.       if (showing) {
  508.         var opacity = 0;
  509.         if (!this.lastShowing) {
  510.           this.cycles = 3;
  511.           this.lastShowing = true;
  512.           opacity = 1;
  513.         }
  514.         if (this.cycles <= 0) return;
  515.         var opacity = opacity || parseFloat(w.style.opacity) || 1;
  516.         if (opacity <= .1) {
  517.            opacity = 1;
  518.            this.cycles --;
  519.         } else {
  520.            opacity -= .05;
  521.         }
  522.         w.style.opacity = opacity;
  523.         if (!once)
  524.           window.setTimeout(function() { gFlashGot.mediaStatusAnim.run(); }, 50);
  525.       } else this.lastShowing = false;
  526.     }
  527.   },
  528.   
  529.   prepareMediaMenu: function(menu) {
  530.     while (menu.firstChild) menu.removeChild(menu.firstChild);
  531.     var m = this.media;
  532.     if (!(m && m.length)) return false;
  533.   
  534.     
  535.     var mi;
  536.     for (var j = 0; j < m.length; j++) {
  537.       menu.appendChild(this._createMediaMenuItem(m[j]));
  538.     }
  539.     return true;
  540.   },
  541.   _createMediaMenuItem: function(l) {
  542.     mi = document.createElement("menuitem");
  543.     mi.setAttribute("label", l.label);
  544.     mi.setAttribute("tooltiptext", l.tip);
  545.     mi.addEventListener("command", function() { gFlashGot.downloadMedia([l]); }, false);
  546.     return mi;
  547.   },
  548.   
  549.  
  550.   get srcWindow() {
  551.     return document.commandDispatcher.focusedWindow;
  552.   }
  553. ,
  554.   get srcDocument() {
  555.     return this.srcWindow.document;
  556.   }
  557. ,
  558.  
  559.   get isTabbed() {
  560.     var b = window.gBrowser;
  561.     return b && b.browsers && b.browsers.length > 1;
  562.   }
  563. ,
  564.   get isSelInvalid() {
  565.     return this.srcWindow.getSelection().isCollapsed && !this.grabSelectedTextFields(null, true);
  566.   }
  567. ,
  568.   get popupLink() { 
  569.     return this.findLinkAsc(document.popupNode);
  570.   }
  571. ,
  572.   get linksCount() {
  573.     const doc = this.srcDocument;
  574.     if(!doc) return 0;
  575.     
  576.     var count = doc.links && doc.links.length || 0;
  577.     
  578.     if(gFlashGotService.getPref("includeImages")) 
  579.        count += (doc.images && doc.images.length) || 0;
  580.     count += (doc.embeds && doc.embeds.length) || 0;
  581.     
  582.     return count;
  583.   }
  584. ,
  585.   getLinks: function(filter, includeImages, doc) {
  586.     if(typeof(doc) != "object") {
  587.       doc = this.srcDocument;
  588.     }
  589.     if(doc == null) return [];
  590.     const allLinks = [];
  591.     const lm = gFlashGotService.lookupMethod;
  592.  
  593.  
  594.     function wrapAndFilter(newL, l) {
  595.       const href = l.src;
  596.       if (!href) return null;
  597.       
  598.       if(href.lastIndexOf("://", 9) < 0) {
  599.         try {
  600.           newL.href = 
  601.                 (uriResolver || 
  602.                  (uriResolver = 
  603.                   Components.classes['@mozilla.org/network/io-service;1']
  604.                             .getService(Components.interfaces.nsIIOService)
  605.                             .newURI(doc.URL, null, null))).resolve(href);
  606.         } catch(ex) {
  607.           return false;
  608.         }
  609.       } else {
  610.         newL.href =  href 
  611.       }
  612.       
  613.       const ga = lm(l, "getAttribute");
  614.       var des = ga("alt") || ga("title") || href.substring(href.lastIndexOf("/") + 1);
  615.       var w, h;
  616.       (w = ga("width")) && (h = ga("height")) && (des += " (" + w + "," + h + ")");
  617.  
  618.       newL.description = des;
  619.  
  620.       return filter(newL, l);
  621.     }
  622.     
  623.     function filterLinks(elems, filter, tagName) {
  624.       const wrap = tagName == "A";
  625.       try {
  626.         if(elems) {
  627.           var l, newL;
  628.           const e_item = lm(elems,"item");
  629.           for(var j = 0, len = lm(elems,"length")(); j < len; j++) {
  630.             l = e_item(j);
  631.             newL = wrap ? gFlashGot._wrapAnchor(l, lm) : { tagName: tagName };
  632.             if(newL && filter(newL, l)) {
  633.               allLinks[allLinks.length] = newL;
  634.             }
  635.           }
  636.         }
  637.       } catch(ex) {}
  638.     }
  639.     
  640.     
  641.     
  642.     filterLinks(doc.links, filter, "A"); 
  643.     
  644.     var uriResolver = null;
  645.     
  646.     if(includeImages) {
  647.       filterLinks(doc.images, wrapAndFilter,"IMG");
  648.     }
  649.     
  650.     filterLinks(doc.embeds,wrapAndFilter,"EMBED");
  651.  
  652.     return allLinks;
  653.   }
  654. ,
  655.   get referrer() {
  656.     if(this._referrer) return this._referrer;
  657.     var docURL = this.srcDocument.URL;
  658.     var gb = docURL && docURL.substring(0,5) == "file:" && this.getBuildGalleryData();
  659.     return gb ? gb.referrer : docURL;
  660.   }
  661. ,  
  662.   set referrer(r) {
  663.     return this._referrer = r; 
  664.   },
  665.   
  666.   getBuildGalleryData: function(doc) {
  667.     doc = doc || window.content.document;
  668.     const props = ['preview', 'content', 'referrer'];
  669.     var gb = {};
  670.     try {
  671.       for each(var p in props) {
  672.         gb[p] = doc.getElementById(p).firstChild.nodeValue;
  673.       }
  674.     } catch(e) {
  675.       gb = null;
  676.     }
  677.     return gb;
  678.   },
  679.   
  680.   grabSelectedTextFields: function(selection, justCheck) {
  681.     const lm = gFlashGotService.lookupMethod;
  682.     const doc = this.srcDocument;
  683.     var ff, f, j;
  684.     const vv = [];
  685.     var selStart, selEnd;
  686.     for each(var t in ["textarea", "input"]) {
  687.       var ff = doc.getElementsByTagName(t);
  688.       for(j = 0; (f = ff[j]); j++) {
  689.         try {
  690.           if(selection && selection.containsNode(f, true)) {
  691.             if(justCheck) return true;
  692.             vv.push(lm(f, "value")());
  693.           }
  694.           else {
  695.             selStart = lm(f, "selectionStart")(), selEnd = lm(f, "selectionEnd")();
  696.             if(selStart < selEnd) {
  697.               if(justCheck) return true;
  698.               vv.push(lm(f, "value")()).substring(selStart, selEnd);
  699.             }
  700.           }
  701.         } catch(e) {}
  702.       }
  703.     }
  704.     return justCheck ? false : vv;
  705.   }
  706. ,
  707.   getSelectionLinks: function(includeImages) {
  708.     const selection = this.srcWindow.getSelection();
  709.     
  710.     // link nodes detection
  711.     var links = this.getLinks(function(link, trueNode) {
  712.       return link && gFlashGot.checkLink(link) && 
  713.         selection.containsNode(trueNode ? trueNode : link, true); 
  714.     }, includeImages); 
  715.     
  716.     var selString = selection.toString();
  717.     
  718.     // add textboxes
  719.     
  720.     selString += this.grabSelectedTextFields(selection).join("\n");
  721.     
  722.     var m;
  723.     
  724.     // password detection
  725.     var pwd = gFlashGotService.getPref("selection.guessPassword", true) &&
  726.         (m = selString.match(/\b(?:password|passw|pass|pwd|pw)\W+(.*)/i)) && m[1];
  727.  
  728.     // text links detection
  729.     m = selString.match(
  730.       /\b(?:(?:h.{2}p|ftp|mms|rtsp|rtmpe?):\/\/|[a-z]+[a-z\d]+\.[a-z\d\-\.]+\/)[^\s]*/gi);
  731.     delete selString;
  732.     var j, k;
  733.     if(m) {
  734.       var descMap = null;
  735.       var href, desc;
  736.       var d, diff;
  737.       
  738.       linksLoop:
  739.       for(j = 0, len = m.length; j < len; j++) {
  740.         desc = m[j];
  741.         href = desc.replace(/^h.{2}p/i, "http").replace(/^([a-z]+[a-z\d]+\.[a-z\d\.]+\/)/i, "http://$1");
  742.         // TODO: riddles like http://rap*dshare.com
  743.         if(href) {
  744.           if(!descMap) { // we use it to avoid textual "quasi-duplicates", as http://somepart...oftheurl
  745.             descMap = {};
  746.             for(k = links.length; k-- > 0;) {
  747.               descMap[links[k].description] = true;
  748.             }
  749.           }
  750.           if (descMap[href] || descMap[desc]) continue;
  751.           if (!/^https?:/.test(desc)) {
  752.             for (d in descMap) {
  753.               diff = d.length - desc.length;
  754.               if (diff >= 0 && d.indexOf(desc) == diff) continue linksLoop; 
  755.             }
  756.           }
  757.           links[links.length] = { href: href, description: m[j] };
  758.         }
  759.       }
  760.     }
  761.     
  762.     if(pwd) {
  763.       var des;
  764.       pwd = " pw: " + pwd;
  765.       for(j = links.length; j-- > 0;) {
  766.         des = links[j].description || "";
  767.         links[j].description = des.substring(0, 4) == "http" ? pwd : des.concat(pwd);
  768.       }
  769.     }
  770.     return links;
  771.   }
  772. ,
  773.   checkLink: function(link) {
  774.     return link.href && /^[a-z]+:\/\/.*|javascript:.*http/i.test(link.href) && !/^(mailto|news|file|data):/i.test(link.href);
  775.   }
  776. ,
  777.   _wrapAnchor: function(node, lm) {
  778.     var isAnchor = (node instanceof HTMLAnchorElement);
  779.     if(isAnchor || node instanceof HTMLAreaElement) {
  780.       var d;
  781.       var href = lm(node, "href")();
  782.       if(href) return { 
  783.         href: href,
  784.         tagName: "A",
  785.         getElementsByTagName: lm(node, "getElementsByTagName"),
  786.         description: isAnchor 
  787.           ? (d = lm(node,"title")()) || 
  788.             (d = lm(node, "innerHTML")()) && d.replace(/<[^>]*>/g, "") 
  789.           : (d = (lm(node, "alt")() || lm(node, "title")())) 
  790.         };
  791.     }
  792.     return null;
  793.   }
  794. ,
  795.   findLinkAsc: function(node) {
  796.      const lm = gFlashGotService.lookupMethod;
  797.      var anchor;
  798.      while(node) {
  799.       anchor = this._wrapAnchor(node, lm);
  800.       if(anchor) return this.checkLink(anchor) ? anchor : null;
  801.       node = node.parentNode;
  802.     }
  803.     return null;
  804.   }
  805. ,
  806.   delayCmd: function(cmd) {
  807.     const pg = this.createProgress();
  808.     pg.update(5);
  809.     window.setTimeout(function() {
  810.       try {
  811.         pg.value = 100;
  812.         gFlashGot["download"+cmd]();
  813.         gFlashGot.showProgress();
  814.       } catch(ex) {
  815.         dump(ex);
  816.       }
  817.     },0);
  818.   }
  819. ,
  820.   
  821.   downloadPopupLink: function(dmName) {
  822.     const link = this.popupLink;
  823.     return link && this.download([link], gFlashGotService.OP_ONE, dmName);
  824.   }
  825. ,
  826.   downloadPopupNodeText: function(dmName) {
  827.     if (!(document.popupNode && document.popupNode.textContent)) return false;
  828.     return this.download([{
  829.       href: document.popupNode.textContent,
  830.       description: "Thunderbird Link"
  831.     }], gFlashGotService.OP_ONE, dmName);
  832.   }
  833. ,
  834.   downloadLink: function(dmName) {
  835.     const sel=this.srcWindow.getSelection();
  836.     var link = !sel.isCollapsed && this._wrapAnchor(sel.anchorNode, gFlashGotService.lookupMethod)
  837.       || this.findLinkAsc(this.hoverElement) || this.findLinkAsc(document.commandDispatcher.focusedElement);
  838.     return link && this.download([link], gFlashGotService.OP_ONE, dmName);
  839.   }
  840. ,
  841.   downloadSel: function(dmName) {
  842.     if(this.isSelInvalid) return false;
  843.     const startTime = new Date().getTime();
  844.     const links = this.getSelectionLinks(gFlashGotService.getPref("includeImages"));
  845.     if(!links.length) return false;
  846.     links.startTime = startTime;
  847.     return this.download(links, gFlashGotService.OP_SEL, dmName);
  848.   }
  849. ,
  850.  WrappedCollection: function(coll) {
  851.   this.item = gFlashGotService.lookupMethod(coll, "item");
  852.   this.length = gFlashGotService.lookupMethod(coll, "length")();
  853.  }
  854. ,
  855.   collectAllLinks: function(doc, tagName) {
  856.     var links = [];
  857.     const includeImages = gFlashGotService.getPref("includeImages");
  858.     if(tagName) {
  859.       var frames = new this.WrappedCollection(doc.getElementsByTagName(tagName));
  860.       const lm = gFlashGotService.lookupMethod;
  861.       var contentDocument;
  862.       for(var j=frames.length; j-->0;) {
  863.         try {
  864.           if((contentDocument = lm(frames.item(j), "contentDocument")())) {
  865.             links = links.concat(
  866.               this.collectAllLinks(contentDocument));
  867.           }
  868.         } catch(ex2) {
  869.         }
  870.       }
  871.     } else {
  872.       links = links.concat(this.getLinks(this.checkLink, includeImages, doc)
  873.         ).concat(this.collectAllLinks(doc, "frame")
  874.         ).concat(this.collectAllLinks(doc, "iframe"));
  875.       this.addMediaLinks(links);
  876.     }
  877.     return links;
  878.   }
  879. ,
  880.   get media() {
  881.     return window.content._flashgotMedia || null;
  882.   },
  883.   
  884.   addMediaLinks: function(links, mm) {
  885.     mm = mm || this.media;
  886.     if (!(mm && mm[0])) return false;
  887.     if (!(links.length || links.referrer)) links.referrer = mm[0].referrer;
  888.     Array.prototype.push.apply(links, mm);
  889.     return true;
  890.   }
  891. ,
  892.   downloadAll: function(dmName) {
  893.     const startTime = new Date().getTime();
  894.     const links = this.collectAllLinks(content.document);
  895.     links.startTime = startTime;
  896.     return this.download(links, gFlashGotService.OP_ALL, dmName);
  897.   }
  898. ,
  899.   downloadTabs: function(dmName) {
  900.     if(!this.isTabbed) return this.downloadAll(dmName);
  901.     const bb = getBrowser().browsers;
  902.     var doc;
  903.     var links=[];
  904.     for (var j = 0, len = bb.length; j<len; j++) 
  905.       if ((doc = bb[j].contentDocument))
  906.         links = links.concat(this.collectAllLinks(doc));
  907.  
  908.     return links.length &&
  909.        this.download(links, gFlashGotService.OP_ALL, dmName);
  910.   }
  911. ,
  912.   downloadMedia: function(mediaLinks, dmName) {
  913.     var links = [];
  914.     return this.addMediaLinks(links, mediaLinks) &&
  915.       this.download(links, gFlashGotService.OP_SEL, dmName);
  916.   }
  917. ,
  918.   download: function(links, opType, dmName) {
  919.     if (!links) {
  920.       // best guess selection/link
  921.       return this.downloadSel() || this.downloadLink();
  922.     }
  923.  
  924.     try {
  925.       links.referrer = links.referrer || this.referrer;
  926.       links.browserWindow = window;
  927.       links.document = this.srcDocument;
  928.     } catch(ex) {}
  929.     
  930.     links.progress = this.createProgress();
  931.     const ret = gFlashGotService.download(links, opType, dmName);
  932.     if(!ret) links.progress.update(100);
  933.     return ret;
  934.   }
  935. ,
  936.   progressList: [],
  937.   createProgress: function(v) {
  938.     return new this.Progress(v);
  939.   },
  940.   Progress: function(v) {
  941.     this.value = v || 0;
  942.     this.showing = false;
  943.     this.update = function(v) {
  944.       if(!this.showing) {
  945.         this.showing = true;
  946.         gFlashGot.progressList.push(this);
  947.       }
  948.       if(typeof(v) == "number") this.value = v;
  949.       gFlashGot.showProgress();
  950.     }
  951.   },
  952.   
  953.   showProgressValue: function(v) {
  954.     document.getElementById("flashgot-progresspanel").setAttribute("collapsed",
  955.         v < 100 ? "false" : "true");
  956.     document.getElementById("flashgot-progressmeter").value = v;
  957.     gFlashGotService.yield();
  958.   },
  959.   
  960.   showProgress: function() {
  961.     const pgl = this.progressList; 
  962.     var len = pgl.length;
  963.     var value;
  964.     if(len > 0) {
  965.       value = 0;
  966.       for(var j = len; j-- > 0;) {
  967.         var v = pgl[j].value;
  968.         if(v < 100) {
  969.           value += v;
  970.         } else {
  971.           pgl.splice(j, 1);
  972.           len--;
  973.         }
  974.       }
  975.       value = len > 0 ? Math.round(value / len) : 100;
  976.     } else {
  977.       value = 100;
  978.     }
  979.     this.showProgressValue(value);
  980.   }
  981. ,
  982.   buildGallery: function() {
  983.     var previewURL = null, contentURL = null;
  984.     var gb = this.getBuildGalleryData();
  985.     if(gb) {
  986.       dump("FGBG: reusing gallery data\n");
  987.       previewURL = gb.preview;
  988.       contentURL = gb.content;
  989.     } else {
  990.       var links=this.getSelectionLinks(true);
  991.       if(!(links && links.length)) {
  992.         dump("FGBG: no selection links, using "); 
  993.         if(this.popupLink) {
  994.          dump("popup link\n");
  995.          links = [this.popupLink];
  996.         } else {
  997.          dump("all links\n");
  998.          links=this.getLinks(this.checkLink, true);
  999.         }
  1000.       }
  1001.       var len;
  1002.       if(links && (len=links.length)) {
  1003.         const previewRX = /\d+.*\.(jpg|jpeg|png|gif|bmp)(\?|$)/i;
  1004.         const contentRX = /\d+.*\.[a-z0-9]{2,4}(\?|$)/i;
  1005.         const lm = gFlashGotService.lookupMethod; 
  1006.         var l, tag, url, imgs, i, iLen, i_item, imgSrc;
  1007.         for(var j=0; j<len && ! (contentURL && previewURL); j++) {
  1008.           l=links[j];
  1009.           tag=l.tagName && l.tagName.toUpperCase();
  1010.           url=l.href;
  1011.           if(tag!="IMG" && contentRX.test(url)) {
  1012.             contentURL=url;
  1013.             if(tag=="A" && l.getElementsByTagName ) {
  1014.               imgs=l.getElementsByTagName("img");
  1015.               i_item=lm(imgs, "item");
  1016.               for(i = 0, iLen = lm(imgs,"length")(); i < iLen; i++) {
  1017.                 imgSrc = lm(i_item(i),"src")();
  1018.                 if(previewRX.test(imgSrc)) {
  1019.                   previewURL = imgSrc;
  1020.                   break;
  1021.                 }
  1022.               }
  1023.             }
  1024.           }
  1025.         }
  1026.         if( (!previewURL) && (tag=="img" || previewRX.test(url)) ) {
  1027.           previewURL=url;
  1028.         } 
  1029.       }
  1030.       if(!previewURL) previewURL="";
  1031.       if(previewURL && !contentURL) contentURL=previewURL;
  1032.     }
  1033.     window.openDialog("chrome://flashgot/content/flashgotGalleryBuilder.xul","_blank",
  1034.       "chrome,dialog,centerscreen,resizable",
  1035.       { 
  1036.         previewURL: previewURL, 
  1037.         contentURL: contentURL, 
  1038.         referrerURL: this.referrer,
  1039.         originalWindow: window,
  1040.         tmpDir: gFlashGotService.tmpDir,
  1041.         prefs:  gFlashGotService.prefs
  1042.       }
  1043.     );
  1044.   }
  1045.  
  1046. }
  1047.  
  1048. window.addEventListener("load", gFlashGot.onload, false);
  1049.  
  1050.  
  1051.  
  1052.